﻿using MebAppMarketplace.Model;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Authentication;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
namespace MebAppMarketplace.Biz
{
    public class UserService : BaseService<Model.User>
    {
        private readonly IHttpContextAccessor _httpContextAccessor;
        private ISession _session => _httpContextAccessor.HttpContext.Session;
        private async Task<AuthenticateInfo> GetAuthenticateInfoAsync()
        {
            var user = _httpContextAccessor.HttpContext.User;
            var info = await _httpContextAccessor.HttpContext.Authentication.GetAuthenticateInfoAsync("Cookies");
            if (info == null)
            {
                throw new Exception("不允许为匿名会话执行该方法");
            }
            return info;
        }
        public UserService(IHttpContextAccessor httpContextAccessor, DbContext db) : base(db)
        {
            _httpContextAccessor = httpContextAccessor;
        }

        public async Task<bool> IsAuthorizedAsync()
        {
            var info = await GetAuthenticateInfoAsync();
            return info.Principal.Identity.IsAuthenticated;
        }

        public async Task<Guid> GetLoginUserIDAsync()
        {
            var info = await GetAuthenticateInfoAsync();
            var userId = info.Principal.Claims.First(x => x.Type == ClaimTypes.NameIdentifier).Value;
            return Guid.Parse(userId);
        }

        public Task<LoginResult> LoginAdmin(string username, string password)
        {
            return Login(username, password, "Admin");
        }

        public Task<LoginResult> LoginDeveloper(string username, string password)
        {
            return Login(username, password, "Developer");
        }

        public Task<LoginResult> LoginUser(string username, string password)
        {
            return Login(username, password, "User");
        }

        public ThreadLocal<Guid> UserID = new ThreadLocal<Guid>();

        public async Task<LoginResult> Login(string username, string password, string role)
        {
            var u = username.ToLower();
            role = $"[{role}]";
            var m = DbSet.Contain(x => x.Roles, role).FirstOrDefault(x => x.UserName == u || x.Email == u);
            if (m == null)
                return LoginResult.账号或密码错误;
            else if (!m.Enabled)
                return LoginResult.账号已禁用;
            else if (!Helpers.Crypto.VerifyHashedPassword(password, m.Password))
                return LoginResult.账号或密码错误;
            var userClaims = new List<Claim> {
                new Claim(ClaimTypes.Name, m.RealName),
                new Claim(ClaimTypes.NameIdentifier, m.ID.ToString()),
                //new Claim(ClaimTypes.Role,string.Join(",",m.Roles.Split(',').Select(x=>x.Trim(new char[]{'[',']' }))))
            };
            foreach (var item in m.Roles.Split(',').Select(x => x.Trim(new char[] { '[', ']' })))
            {
                userClaims.Add(new Claim(ClaimTypes.Role, item));
            }
            var principal = new ClaimsPrincipal(new ClaimsIdentity(userClaims, typeof(UserService).Name));

#if NETCOREAPP1_1
            await _httpContextAccessor.HttpContext.Authentication.SignInAsync("Cookies", principal);
#endif
#if NETCOREAPP2_0
            await _httpContextAccessor.HttpContext.SignInAsync("Cookies", principal);
#endif

            UserID.Value = m.ID;
            return LoginResult.登录成功;
        }

        public List<Model.User> GetUserList(int page)
        {
            return DbSet.GetList(page);
        }

        public bool IsRegisterExists(string email)
        {
            var service = this.AsService<Model.UserRegistrationRequest>();
            return service.DbSet.Any(x => x.Email == email.ToLower() && x.AuditTime != null);
        }

        public List<Model.UserRegistrationRequest> GetRegisterList(int page)
        {
            var service = this.AsService<Model.UserRegistrationRequest>();
            return service.DbSet.GetList(page);
        }

        public void AddRegisterRequest(string realName, string email, string message)
        {
            var service = this.AsService<Model.UserRegistrationRequest>();
            var model = new Model.UserRegistrationRequest();
            model.ID = Guid.NewGuid();
            model.RealName = realName;
            model.Message = message;
            model.Email = email.ToLower();
            model.CreateTime = DateTime.Now;
            service.DbSet.Add(model);
            service.Db.SaveChanges();
        }

        public bool IsRegistrationAudited(Guid id)
        {
            var service = this.AsService<Model.UserRegistrationRequest>();
            var model = service.DbSet.Find(id);
            return model.AuditState != AuditState.待审核;
        }

        private Guid AdministratorID = Guid.Parse("9978da57-1788-42aa-9d44-3c288866bcde");
        public void InitializeAdmin()
        {
            if (!DbSet.Any(x => x.ID == AdministratorID))
            {
                var user = new User();
                user.ID = AdministratorID;
                user.RealName = "Admin";
                user.Enabled = true;
                user.Email = "tiny@sandsea.info";
                user.CreateTime = DateTime.Now;
                user.Roles = "[User],[Developer],[Admin]";
                DbSet.Add(user);
                Db.SaveChanges();
                this.SetPassword(user.ID, "123456");
            }
        }

        public void ApproveRegistration(Guid id)
        {
            var service = this.AsService<Model.UserRegistrationRequest>();
            var model = service.DbSet.Find(id);
            model.AuditTime = DateTime.Now;
            model.AuditState = AuditState.审核通过;
            service.Db.Entry(model).State = EntityState.Modified;

            //TODO: send email with a link used to set password and username

            var user = new User();
            user.ID = Guid.NewGuid();
            user.RealName = model.RealName;
            user.Email = model.Email;
            user.CreateTime = model.AuditTime.Value;
            user.Roles = "User";
            DbSet.Add(user);
            service.Db.SaveChanges();
        }

        public void SetPassword(Guid id, string password)
        {
            var m = DbSet.Find(id);
            m.Password = Helpers.Crypto.HashPassword(password);
            Db.Entry(m).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
            Db.SaveChanges();
        }

        public void SetRole(Guid id, string role)
        {
            var m = DbSet.Find(id);
            m.Roles = role;
            Db.Entry(m).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
            Db.SaveChanges();
        }

        public void DisableUser(Guid id)
        {
            var m = DbSet.Find(id);
            if (!m.Enabled)
                return;
            m.Enabled = false;
            Db.Entry(m).State = EntityState.Modified;
            Db.SaveChanges();
            return;
        }

        public void EnableUser(Guid id)
        {
            var m = DbSet.Find(id);
            if (m.Enabled)
                return;
            m.Enabled = true;
            Db.Entry(m).State = EntityState.Modified;
            Db.SaveChanges();
            return;
        }

        public void RejectRegistration(Guid id, string reason)
        {
            var service = this.AsService<Model.UserRegistrationRequest>();
            var model = service.DbSet.Find(id);
            model.AuditTime = DateTime.Now;
            model.AuditState = AuditState.审核驳回;
            model.RejectReason = reason;
            service.Db.Entry(model).State = EntityState.Modified;
            service.Db.SaveChanges();
        }
    }
}
